/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  slup.h
 *         \unit  slup
 *        \brief  This is a simple serial link universal protocol for C language
 *       \author  Lamdonn
 *      \version  v0.1.0
 *      \license  GPL-2.0
 *    \copyright  Copyright (C) 2023 Lamdonn.
 ********************************************************************************************************/
#ifndef __slup_H
#define __slup_H

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

/* Version infomation */
#define SLUP_V_MAJOR                        0
#define SLUP_V_MINOR                        1
#define SLUP_V_PATCH                        0

// Maximum size of the head part in the SLUP structure, set to 4 bytes.
#define SLUP_HEAD_MAX                       4
// Maximum size of the tail part in the SLUP structure, set to 4 bytes.
#define SLUP_TAIL_MAX                       4
// Maximum size of the check code part in the SLUP structure, set to 4 bytes.
#define SLUP_CHECK_MAX                      4
// Maximum size of the sequence number (SN) part in the SLUP structure, set to 4 bytes.
#define SLUP_SN_MAX                         4
// Maximum size of the frame in the SLUP structure, set to 4095 bytes.
#define SLUP_FRAME_MAX                      4095
// Size of the receive queue in the SLUP structure, set to 1024 bytes.
#define SLUP_RXQUE_SIZE                     1024

// Success code, indicating that an operation has been completed successfully.
#define SLUP_E_OK                           0  
// Error code, indicating that the 'slup' pointer is invalid.
#define SLUP_E_INVALID                      1  
// Error code, indicating that the 'data' pointer is invalid.
#define SLUP_E_DATA                         2  
// Error code, indicating that the length value is invalid.
#define SLUP_E_LEN                          3  
// Error code, indicating that the SLUP load testing has not started.
#define SLUP_E_NTEST                        4  
// Error code, indicating that the SLUP load exceeds the defined range.
#define SLUP_E_OVER                         5  
// Error code, indicating that the 'link' pointer is invalid.
#define SLUP_E_LINK                         6  
// Error code, indicating that the 'rate' pointer is invalid.
#define SLUP_E_RATE                         7  

// Link status value representing the link is in the down state.
#define SLUP_LINK_DOWN                      0x00
// Link status value representing the link is in the transmit (TX) state.
#define SLUP_LINK_TX                        0x01
// Link status value representing the link is in the receive (RX) state.
#define SLUP_LINK_RX                        0x02
// Link status value representing the link is in the up state.
#define SLUP_LINK_UP                        0x03

// Function pointer type for a function that writes a character.
// It takes a character 'c' as an argument and returns an 'int'.
typedef int (*slup_putc_t)(char c);

// Function pointer type for a function that checks data.
// It takes a pointer to an array of 'uint8_t' data and its length (in 'uint16_t') as arguments
// and returns a 'uint32_t'.
typedef uint32_t (*slup_check_t)(uint8_t *data, uint16_t length);

// Function pointer type for a function that receives data.
// It takes a pointer to an array of 'uint8_t' data and its length (in 'uint16_t') as arguments
// and returns an 'int'.
typedef int (*slup_receive_t)(uint8_t *data, uint16_t length);

// Structure definition for SLUP configuration.
typedef struct 
{
    // Array to store the head mask, with a maximum size defined by SLUP_HEAD_MAX.
    uint8_t head[SLUP_HEAD_MAX];            /**< head mask */
    // Array to store the tail mask, with a maximum size defined by SLUP_TAIL_MAX.
    uint8_t tail[SLUP_TAIL_MAX];            /**< tail mask */
    // Size of the head part, stored in 4 bits.
    uint8_t hsize : 4;                      /**< head size */
    // Size of the tail part, stored in 4 bits.
    uint8_t tsize : 4;                      /**< tail size */
    // Size of the check code part, stored in 4 bits.
    uint8_t csize : 4;                      /**< check code size */
    // Size of the sequence number (sn) part, stored in 4 bits.
    uint8_t ssize : 4;                      /**< sn size */
} SLUP_CFG;

/* queue type define */
// Structure definition for an SLUP queue.
typedef struct
{
    // Array that serves as the base address for the data in the queue,
    // with a size defined by SLUP_RXQUE_SIZE.
    char base[SLUP_RXQUE_SIZE];             /* base address of data */
    // Total size of the queue.
    uint32_t size;                          /* size of queue */
    // Index of the queue head.
    uint32_t head;                          /* index of queue head */
    // Index of the queue tail.
    uint32_t tail;                          /* index of queue tail */
} SLUP_QUEUE;

// Structure definition for an SLUP parser.
typedef struct 
{
    // Current state of the parser.
    uint8_t state;
    // Index related to the head part, stored in 4 bits.
    uint8_t hindex : 4;    
    // Index related to the tail part, stored in 4 bits.
    uint8_t tindex : 4; 
    // Index related to the check code part, stored in 4 bits.
    uint8_t cindex : 4;                     
    // Index related to the sequence number (sn) part, stored in 4 bits.
    uint8_t sindex : 4;  
    // Index related to the length part, stored in 2 bits.
    uint8_t lindex : 2;                    
    // Flag indicating the frame status.
    uint8_t frame;
    // Length of the data being processed.
    uint16_t length;
    // Index within the data.
    uint16_t dindex;
    // Check value for the data.
    uint32_t check;
    // Sequence number.
    uint32_t sn;
} SLUP_PARSER;

// Structure definition for an SLUP dummy data structure.
typedef struct 
{
    // Compression factor, represented as a floating-point number.
    float compression;
    // Rate value, represented as a floating-point number.
    float rate;
    // Target value, represented as a 32-bit unsigned integer.
    uint32_t target;
    // Base value for the gap, represented as a 32-bit unsigned integer.
    uint32_t gapbase;
    // Count value for the gap, represented as a 32-bit unsigned integer.
    uint32_t gapcount;
    // Array to store data, with a size of 64 bytes.
    uint8_t data[64];
} SLUP_DUMMY;

// Structure definition for the main SLUP structure that combines multiple components.
typedef struct 
{
    // SLUP configuration structure.
    SLUP_CFG cfg;
    // SLUP queue structure.
    SLUP_QUEUE queue;
    // SLUP parser structure.
    SLUP_PARSER parser;
    // SLUP dummy data structure.
    SLUP_DUMMY dummy;
    // Buffer to store data, with a maximum size defined by SLUP_FRAME_MAX.
    uint8_t buffer[SLUP_FRAME_MAX];
    // Size of the buffer.
    uint32_t bsize;
    // Sequence number.
    uint32_t sn;
    // Link status flag.
    uint8_t link;
    // Silent status flag.
    uint8_t silent;
    // Period value, represented as a 16-bit unsigned integer.
    uint16_t period;
    // Timestamp value, represented as a 32-bit unsigned integer.
    uint32_t timestamp;
    // Number of bits for the up direction, represented as a 32-bit unsigned integer.
    uint32_t upbits;
    // Number of bits for the down direction, represented as a 32-bit unsigned integer.
    uint32_t downbits;
    // Rate value for the up direction, represented as a 32-bit unsigned integer.
    uint32_t uprate;
    // Rate value for the down direction, represented as a 32-bit unsigned integer.
    uint32_t downrate;
    // Function pointer of type 'slup_putc_t' for writing a character.
    slup_putc_t putc;
    // Function pointer of type 'slup_check_t' for checking data.
    slup_check_t check;
    // Function pointer of type 'slup_receive_t' for receiving data.
    slup_receive_t receive;
} SLUP;

/**
 * \brief Initializes the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \return SLUP_E_OK if the initialization is successful, SLUP_E_INVALID if the pointer is NULL.
 * 
 * This function initializes various fields in the SLUP structure.
 */
int slup_init(SLUP *slup);

/**
 * \brief Sends data in the SLUP protocol with a frame type of 0x01.
 * \param slup: Pointer to the SLUP structure.
 * \param data: Pointer to the data buffer to be sent.
 * \param length: The length of the data buffer.
 * \return SLUP_E_OK if the data is successfully sent, appropriate error code otherwise.
 * 
 * This function simply calls the slup_send_package function with a frame type of 0x01
 * to send the provided data.
 */
int slup_send(SLUP *slup, uint8_t *data, uint16_t length);

/**
 * \brief Retrieves the current link status from the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param link: Pointer to a variable where the link status will be stored.
 * \return SLUP_E_OK if the retrieval is successful, appropriate error code otherwise.
 * 
 * This function checks if the provided pointers are valid. 
 */
int slup_link_status(SLUP *slup, uint8_t *link);

/**
 * \brief Retrieves the upload rate from the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param rate: Pointer to a variable where the upload rate will be stored.
 * \return SLUP_E_OK if the retrieval is successful, appropriate error code otherwise.
 * 
 * This function checks if the provided pointers are valid. 
 */
int slup_upload_rate(SLUP *slup, uint32_t *rate);

/**
 * \brief Retrieves the download rate from the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param rate: Pointer to a variable where the download rate will be stored.
 * \return SLUP_E_OK if the retrieval is successful, appropriate error code otherwise.
 * 
 * This function checks if the provided pointers are valid. 
 */
int slup_download_rate(SLUP *slup, uint32_t *rate);

/**
 * \brief Sets the target rate for the dummy data in the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param rate: The target rate value to be set.
 * \return SLUP_E_OK if the setting is successful, SLUP_E_INVALID if the pointer is NULL.
 * 
 * This function checks if the provided pointer is valid. 
 */
int slup_set_dummy(SLUP *slup, uint32_t rate);

/**
 * \brief Handles the reception of a single character in the SLUP system.
 * \param slup: Pointer to the SLUP structure.
 * \param c: The received character.
 * 
 * This function updates the link status to indicate a received character (sets SLUP_LINK_RX),
 * clears the silent flag, updates the download statistics, and pushes the received character
 * into the queue.
 */
void slup_getc(SLUP *slup, char c);

/**
 * \brief The main task function for the SLUP system.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function is the main task handler for the SLUP system. It updates the timestamp,
 * and based on the timestamp value, performs various operations such as sending heartbeat
 * messages, calculating rates, executing dummy data sending, and updating dummy data parameters.
 * It also calls the slup_parse_task function to parse the received data in the queue.
 */
void slup_task(SLUP *slup);

#endif
